package znet

import (
	"errors"
	"fmt"
	"io"
	"net"
	"zinx/ziface"
)

/*
链接模块
*/
type Connection struct {
	//当前链接的socket TCP套接字
	Conn *net.TCPConn

	//链接的ID
	ConnId uint32

	//当前的链接状态
	isClosed bool

	//当前链接所绑定的处理业务的方法API
	//handleApi ziface.HandleFunc

	//告知当前链接已经退出/停止的 channel(由Reader告知Writer退出)
	ExitChan chan bool

	//用于读和写之间通信的缓存通道
	MsgChan chan []byte

	//该链接处理的方法Router
	// Router ziface.IRouter
	MsgHandler ziface.IMsgHandler
}

// 初始化链接模块的方法
func NewConnection(conn *net.TCPConn, connID uint32, msgHandler ziface.IMsgHandler) *Connection {
	return &Connection{
		Conn:   conn,
		ConnId: connID,
		//handleApi: callback_api,
		isClosed: false,
		ExitChan: make(chan bool, 1),
		MsgChan:  make(chan []byte),
		// Router:   router,
		MsgHandler: msgHandler,
	}
}

// 从客户端链接读取业务方法
func (c *Connection) StartReader() {
	fmt.Println("Reader Start().... ConnId=", c.ConnId)
	defer c.Stop()
	for {
		//读取客户端的数据到buf中，最大字节512
		// buf := make([]byte, utils.GlobalObject.MaxPacketSize)
		// _, err := c.Conn.Read(buf)
		// if err != nil {
		// 	fmt.Println("receive buf err", err)
		// 	continue
		// }
		////调用当前链接绑定的HandleAPI
		//if err := c.handleApi(c.Conn, buf, cnt); err != nil {
		//	fmt.Println("ConnId=", c.ConnId)
		//	break
		//}

		// 创建拆包对象
		dp := NewDataPack()

		//读取客户端的Msg head
		headData := make([]byte, dp.GetHeadLen())
		if _, err := io.ReadFull(c.GetTCPConnection(), headData); err != nil {
			fmt.Println("read msg head err", err)
			break
		}

		//拆包，得到msgID和msgDatalen 放在msg中
		msg, err := dp.Unpack(headData)
		if err != nil {
			fmt.Println("unpack err:", err)
			break
		}

		//根据 dataLen 读取data，放在msg.Data中
		var data []byte
		if msg.GetMsgLen() > 0 {
			data = make([]byte, msg.GetMsgLen())
			if _, err := io.ReadFull(c.GetTCPConnection(), data); err != nil {
				fmt.Println("read msg data err:", err)
				break
			}
		}
		msg.SetData(data)

		//得到当前conn数据的Request请求数据
		req := Request{
			conn: c,
			msg:  msg,
		}

		//从路由中，找到注册绑定的Conn对应的router调用
		go c.MsgHandler.DoMsgHandler(&req)

		// go func(request ziface.IRequest) {
		// 	//执行路由方法
		// 	c.Router.PostHandle(request)
		// 	c.Router.Handle(request)
		// 	c.Router.PostHandle(request)
		// }(&req)
	}
}

// 从客户端链接写业务方法
func (c *Connection) StartWriter() {
	fmt.Println("[Writer Goroutine is running]")
	defer fmt.Println(c.Conn.RemoteAddr().String(), "[conn Writer exit!]")
	for {
		select {
		case data := <-c.MsgChan:
			//有数据要写给客户端
			if _, err := c.Conn.Write(data); err != nil {
				fmt.Println("conn write err:", err)
				return
			}
		case <-c.ExitChan:
			//代表Reader已经退出，Writer也需要退出
			return
		}
	}
}

// 启动链接 让当前的链接准备开始工作
func (c *Connection) Start() {
	fmt.Println("Conn Start().... ConnId=", c.ConnId)
	//启动从当前链接读数据的业务
	go c.StartReader()
	//启动从当前链接写数据的业务
	go c.StartWriter()
}

// 停止链接 结束当前链接的工作
func (c *Connection) Stop() {
	fmt.Println("Conn Stop().... ConnId=", c.ConnId)

	//如果当前链接已经关闭
	if c.isClosed == true {
		return
	}
	c.isClosed = true

	//关闭stock链接
	c.Conn.Close()

	//告知Wrietr关闭
	c.ExitChan <- true

	//回收资源
	close(c.ExitChan)
	close(c.MsgChan)
}

// 获取当前链接绑定的socket conn
func (c *Connection) GetTCPConnection() *net.TCPConn {
	return c.Conn
}

// 获取当前链接模块的链接ID
func (c *Connection) GetConnId() uint32 {
	return c.ConnId
}

// 获取远程客户端的TCP状态 Ip port
func (c *Connection) GetRemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}

// 直接将Message数据发送数据给远程的TCP客户端
func (c *Connection) SendMsg(msgId uint32, data []byte) error {
	if c.isClosed == true {
		return errors.New("connection closed when send msg")
	}
	//将data封包，并且发送
	dp := NewDataPack()
	msg, err := dp.Pack(NewMsgPackage(msgId, data))
	if err != nil {
		fmt.Println("Pack error msg id = ", msgId)
		return errors.New("Pack error msg ")
	}
	//写回客户端
	// if _, err := c.Conn.Write(msg); err != nil {
	// 	fmt.Println("Send msg id = ", msgId, " error")
	// 	return errors.New("Send msg error")
	// }
	//写到Writer的MsgChan中
	c.MsgChan <- msg
	return nil
}
